﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;

namespace RecaptchaMvc {
	public class RecaptchaValidator : IRecaptchaValidator {
		private const string _verifyUrl = "http://api-verify.recaptcha.net/verify";

		public RecaptchaValidator() : this(30000) {}
		public RecaptchaValidator(int timeout) {
			this.Timeout = timeout;
		}

		public int Timeout { get; set; }

		protected virtual byte[] GetFormData(IRecaptchaRequest request) {
			StringBuilder builder = new StringBuilder();
			builder.Append("privatekey=");
			builder.Append(HttpUtility.UrlEncode(request.PrivateKey));
			builder.Append("&remoteip=");
			builder.Append(HttpUtility.UrlEncode(request.RemoteIP));
			builder.Append("&challenge=");
			builder.Append(HttpUtility.UrlEncode(request.Challenge));
			builder.Append("&response=");
			builder.Append(HttpUtility.UrlEncode(request.Response));
			return Encoding.ASCII.GetBytes(builder.ToString());
		}
		protected virtual WebRequest GetWebRequest() {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(RecaptchaValidator._verifyUrl);
			request.ProtocolVersion = HttpVersion.Version10;
			request.Timeout = this.Timeout;
			request.Method = "POST";
			request.UserAgent = "reCAPTCHA/ASP.NET MVC";
			request.ContentType = "application/x-www-form-urlencoded";
			return request;
		}
		public virtual IRecaptchaResponse Validate(IRecaptchaRequest request) {
			if(string.IsNullOrEmpty(request.Challenge) || string.IsNullOrEmpty(request.Response))
				return RecaptchaResponse.InvalidSolution;
			WebRequest webRequest = this.GetWebRequest();
			byte[] data = this.GetFormData(request);
			using(Stream stream = webRequest.GetRequestStream()) {
				stream.Write(data, 0, data.Length);
			}
			string[] results = null;
			try {
				using(WebResponse webResponse = webRequest.GetResponse()) {
					using(TextReader reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8)) {
						results = reader.ReadToEnd().Split();
					}
				}
			}
			catch(WebException ex) {
				return RecaptchaResponse.RecaptchaNotReachable;
			}

			if(string.Equals(results[0], "true", StringComparison.OrdinalIgnoreCase))
				return RecaptchaResponse.Valid;
			return new RecaptchaResponse(false, results[1]);
		}
	}
}